home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 33 / Amiga Format AFCD33 (Issue 117, Dec 1998).iso / -seriously_amiga- / programming / e / kyz_obj / doc / patch.doc < prev    next >
Text File  |  1998-09-14  |  12KB  |  316 lines

  1. TABLE OF CONTENTS
  2.  
  3. patch.m/--overview--
  4. patch.m/disable
  5. patch.m/enable
  6. patch.m/end
  7. patch.m/install
  8. patch.m/patched_function
  9. patch.m/remove
  10. patch.m/--overview--                                     patch.m/--overview--
  11.  
  12.    PURPOSE
  13.     To allow easy patching of Amiga library and device functions
  14.     with Amiga E code.
  15.  
  16.    OVERVIEW
  17.     The AmigaOS has a facility to change the code called in any of the
  18.     functions  of  a  library  or  device.  But due to the way Amiga E
  19.     works, it has been difficult to easily use E code as patches.
  20.  
  21.     This  object  allows  you  to  install patches to the system using
  22.     Amiga E code in the most flexible way, via an assembler wedge.
  23.  
  24.     Installation:
  25.  
  26.     You  first  need  to open the library/device that you are going to
  27.     patch.  You  then  need  to  know the Library Vector Offset of the
  28.     entry  you  are  going to patch. This is available using the 'lvo'
  29.     tool  from  the  Developer Kit, or any assembler include file with
  30.     'LVO'  in the title. You must keep the library/device open for the
  31.     entire  duration  of  the patch. If you do not, the library may be
  32.     flushed from memory and loaded somewhere else, indirectly removing
  33.     the  patch  and  also  causing  a  crash when we try to remove our
  34.     defunct patch later.
  35.  
  36.     You create a patch object with install(), to install a wedge which
  37.     calls an E function which you defined like so:
  38.  
  39.         PROC patch_code(function, a7,a6,a5,a4,a3,a2,a1,a0,
  40.                                   d7,d6,d5,d4,d3,d2,d1,d0)
  41.  
  42.     You  can give alternate names to the 'register' parameters, but do
  43.     remember  that  they  will  always  be  passed IN THE ABOVE-STATED
  44.     ORDER, and writing the parameter's names in a different order will
  45.     NOT cause the registers to be passed to you in a different order.
  46.  
  47.     See patched_function() for more about this.
  48.  
  49.     Your patch in operation:
  50.  
  51.     This  E  function is called 'as' the function you have patched, by
  52.     absolutely  any  task  and  program  that  could call the original
  53.     function.  Also,  the  function  may  be  called  by more than one
  54.     program  at  once,  so  use a Semaphore or similar protection when
  55.     using global variables.
  56.  
  57.     You are given all the registers as set when the patch was called -
  58.     do  NOT modify them unless it is documented that the function does
  59.     this.  That said, you can always modify the 'd0' variable as it is
  60.     ignored  on exit, the return value of your function is returned in
  61.     D0 rather than the stack-based copy.
  62.  
  63.     Occasionally  you  can modify the 'scratch register' variables d0,
  64.     d1,  a0  and  a1,  but  you  must  check  the documentation of the
  65.     function  you  are  patching,  to  ensure  it  does not promise to
  66.     preserve any of these registers.
  67.  
  68.     The result of your function call is always returned in D0, but E's
  69.     multiple return values (in D1 and D2) are ignored, and restored to
  70.     their original values.
  71.  
  72.     Calling the original function:
  73.  
  74.     You  are  also  given  a pointer to the original function you have
  75.     patched.  In  most  patches,  you  will  have to call the original
  76.     function sometime, so you would set up the registers appropriately
  77.     from  the parameters, including A6 as the library/device base, and
  78.     call  the  original  function.  Do  NOT  do  this by writing the E
  79.     construct "function()", as this will use an unspecified A-register
  80.     to  make  the  call. Instead, do it yourself with another register
  81.     that  you choose. If you need to pass A0 to A3 as parameters, then
  82.     you will have to preserve and use A4 or A5.
  83.  
  84.     Patch removal:
  85.  
  86.     Your  patch  can be either enabled or disabled. When disabled, the
  87.     assembler  wedge  simply  hops  to  the  original function, adding
  88.     nothing  to  the  stack. Simply exiting your program at this point
  89.     without  ENDing  the  object would free the object instance itself
  90.     but  would leave the working wedge in place, consuming 70 bytes of
  91.     memory and adding 3 instructions to the function.
  92.  
  93.     Some  people  would  advocate  exiting your program with the wedge
  94.     still in place, as the user is unlikely to do that often, but when
  95.     they do there will be no problem with exiting correctly.
  96.  
  97.     Others  would always recommend total removal of the patch, even if
  98.     that  means  waiting. Unlike other wedges, the removal method used
  99.     by  this  object is very safe, only removes the patch if it is not
  100.     being  used,  and understands programs like SetFunction Manager or
  101.     SaferPatches which allow removal of patches in any order.
  102.  
  103.     My  advice  is to always disable() the patch, then try to remove()
  104.     the  patch. If that fails, ask the user if you should keep trying,
  105.     or just exit.
  106.  
  107.    WARNING
  108.     When your patch is enabled, the combination of assembler wedge and
  109.     E code will add a MINIMUM of 80 bytes - THEN extra bytes are added
  110.     for the variables in your patch! There is NO stack checking made!
  111.  
  112.     You should avoid local variables at all costs, use the full REG=5
  113.     optimisation, and avoid defining STRINGs or LISTs as variables.
  114.  
  115.     More warnings will be pasted in here when I can find the message
  116.     about patches that I posted to the E list.
  117.  
  118. patch.m/disable                                               patch.m/disable
  119.  
  120.    NAME
  121.     patch.disable() -- prevent further execution of the patch.
  122.  
  123.    SYNOPSIS
  124.     disable()
  125.  
  126.    FUNCTION
  127.     Stops the patch from being invoked again. All calls to the patched
  128.     function  will be passed directly to the original function, not to
  129.     your patch.
  130.  
  131.     There  may,  however, still be invocations of the patch running at
  132.     the time this call returns.
  133.  
  134.    SEE ALSO
  135.     enable()
  136.  
  137. patch.m/enable                                                 patch.m/enable
  138.  
  139.    NAME
  140.     patch.enable() -- allow execution of the patch.
  141.  
  142.    SYNOPSIS
  143.     enable()
  144.  
  145.    FUNCTION
  146.     Toggles a switch in the assembler wedge which stops it passing all
  147.     calls of the patched function to the original function, and starts
  148.     passing them to your patch.
  149.  
  150.     Your  patch  should  be ready to run at any time from the start of
  151.     the call to this method.
  152.  
  153.    SEE ALSO
  154.     disable()
  155.  
  156. patch.m/end                                                       patch.m/end
  157.  
  158.    NAME
  159.     patch.end() -- Destructor.
  160.  
  161.    SYNOPSIS
  162.     end()
  163.  
  164.    FUNCTION
  165.     Frees  resources  used  by an instance of the patch class. It will
  166.     first  disable() the patch, then it will busy loop until the patch
  167.     is successfully removed.
  168.  
  169.    SEE ALSO
  170.     disable(), remove(), install()
  171.  
  172. patch.m/install                                               patch.m/install
  173.  
  174.    NAME
  175.     patch.install() -- Constructor.
  176.  
  177.    SYNOPSIS
  178.     install(base, offset, patchfunc)
  179.     install(base, offset, patchfunc, userdata)
  180.  
  181.    FUNCTION
  182.     Initialises  an  instance of the patch class, and installs a patch
  183.     in the system. The patch will not be enabled to begin with, so you
  184.     must  call  enable()  on  the  patch  for it to start working. The
  185.     exception "MEM" will be raised if there is no memory for a wedge.
  186.  
  187.     Read patched_function() to see how this patch is called.
  188.  
  189.    INPUTS
  190.     base      - the  base  of  the library or device of whose function
  191.                 you  will  be  patching. It should remain open for the
  192.                 entire  life of the patch, otherwise it may be flushed
  193.                 from memory, rendering the patch useless.
  194.  
  195.     offset    - This  is the Library Vector Offset of the function you
  196.                 are patching. The appropriate number is available from
  197.                 LVO files or the 'lvo' tool.
  198.  
  199.     patchfunc - The address of the Amiga E function which will replace
  200.                 the specified device/library function.
  201.  
  202.     userdata  - An optional parameter that can be anything you want it
  203.                 to be. It will be passed to your E function as a LONG,
  204.                 whether or not you define or use it. The default value
  205.                 for this parameter is zero.
  206.  
  207.    SEE ALSO
  208.     end(), enable(), patched_function()
  209.  
  210. patch.m/patched_function                             patch.m/patched_function
  211.  
  212.    NAME
  213.     patched_function() -- how your installed patch is called.
  214.  
  215.    SYNOPSIS
  216.     result := patched_function(
  217.                 original_function,
  218.                 a7,a6,a5,a4,a3,a2,a1,a0,d7,d6,d5,d4,d3,d2,d1,d0
  219.               )
  220.  
  221.     result := patched_function(
  222.                 userdata, original_function,
  223.                 a7,a6,a5,a4,a3,a2,a1,a0,d7,d6,d5,d4,d3,d2,d1,d0
  224.               )
  225.  
  226.    FUNCTION
  227.     When  you  install  a  patch,  your  patch function will be called
  228.     instead  of  the original function. Rather than your function code
  229.     being  installed  directly as the new patch, an assembler wedge is
  230.     instead used. This allows for the patch to be enabled and disabled
  231.     with  ease, and also prepares the correct environment for an Amiga
  232.     E function to operate.
  233.  
  234.     The  wedge  prepares a set of arguments on the stack for the patch
  235.     function,  so  that it can know everything neccessary to implement
  236.     the patch.
  237.  
  238.    INPUTS
  239.     userdata          - this  value  was chosen by the programmer when
  240.                         installing the patch.
  241.  
  242.                         This  userdata  value is passed whether or not
  243.                         it  was requested in the installation, and the
  244.                         way Amiga E defines function parameters allows
  245.                         you  to either define your function so that it
  246.                         knows  the  userdata  value, or it doesn't (as
  247.                         shown above).
  248.  
  249.                         The  userdata  value  can  enable you to write
  250.                         only  one  function  to patch multiple library
  251.                         functions  - each patch would have a different
  252.                         userdata  parameter,  and the patch code would
  253.                         use  this  to  recognise which function it was
  254.                         patching when called.
  255.  
  256.     original_function - this  is  a  pointer  to  the  code that would
  257.                         normally  be  executed,  if your patch was not
  258.                         installed. In most patches, you do not replace
  259.                         the  entire  functionality  of  the patch, and
  260.                         therefore have to use this pointer to call the
  261.                         original  function. Remember to initialise all
  262.                         required   parameters  (including  A6)  before
  263.                         calling this function.
  264.  
  265.     a7, a6, a5, a4,   - these  are  the  68000 registers as set before
  266.     a3, a2, a1, a0,     your  patch  was called. Some of these will be
  267.     d7, d6, d5, d4,     parameters to your patch, others will be of no
  268.     d3, d2, d1, d0      use,  but  you  can  NOT remove them from your
  269.                         function  declaration.  You  may  assign names
  270.                         other  than their real register names to them,
  271.                         perhaps  to  mirror  the  declaration  of  the
  272.                         patched function - but be warned that you must
  273.                         NOT  modify  these  variables, as they will be
  274.                         restored  to  the  registers  on  exit of your
  275.                         function.  The  only  parameter you can safely
  276.                         alter  is  the 'd0' parameter, as its contents
  277.                         are ignored on your function exit, instead the
  278.                         function's return value is used for D0.
  279.  
  280.                         These  parameters  are  always  defined in the
  281.                         same order - from A7 to A0, then D7 to D0.
  282.  
  283.    RESULT
  284.     The  value  you return from your patch function is always returned
  285.     in  D0 by normal E standards. The assembler wedge avoids restoring
  286.     the  original  value  of  D0 it picked up on entry, so this result
  287.     stays.   Some  functions  declare  that  they  return  results  in
  288.     registers  other  than  D0,  so you will have to store those other
  289.     results  in the appropriate 'register' parameters that were passed
  290.     in  to  your function. On return, those variables will be restored
  291.     into the appropriate 68000 registers.
  292.     
  293. patch.m/remove                                                 patch.m/remove
  294.  
  295.    NAME
  296.     patch.remove() -- attempt to remove the patch.
  297.  
  298.    SYNOPSIS
  299.     removed := remove()
  300.  
  301.    FUNCTION
  302.     Attempts  to  remove  the  patch  from the system, and restore the
  303.     original  function. If the patch is successfully removed, there is
  304.     nothing you can do but END the patch.
  305.  
  306.    RESULT
  307.     removed - TRUE if removal of the patch was successful.
  308.  
  309.    NOTE
  310.     You  may  have a greater chance of successful removal of the patch
  311.     if you disable() it first.
  312.  
  313.    SEE ALSO
  314.     end(), disable()
  315.  
  316.